﻿using System.Collections.Generic;
using System.IO;
using System.Xml;
using CodePlex.TeamFoundation.Adapters;
using CodePlex.TeamFoundation.Adapters.WorkItemTracking;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;

namespace CodePlex.TeamFoundation.Utilities.Test
{


  /// <summary>
  ///This test class contains all the unit tests for 
  ///CodePlex.TeamFoundation.Utilities.BuildUtilities
  ///</summary>
  [TestClass()]
  public class RhinoBuildUtilitiesTests
  {

    private TestContext testContextInstance;

    /// <summary>
    ///Gets or sets the test context which provides
    ///information about and functionality for the current test run.
    ///</summary>
    public TestContext TestContext
    {
      get
      {
        return testContextInstance;
      }
      set
      {
        testContextInstance = value;
      }
    }

    #region Additional test attributes
    // 
    //You can use the following additional attributes as you write your tests:
    //
    //Use ClassInitialize to run code before running the first test in the class
    //[ClassInitialize()]
    //public static void MyClassInitialize(TestContext testContext)
    //{
    //}
    //
    //Use ClassCleanup to run code after all tests in a class have run
    //[ClassCleanup()]
    //public static void MyClassCleanup()
    //{
    //}
    //
    //Use TestInitialize to run code before running each test
    //[TestInitialize()]
    //public void MyTestInitialize()
    //{
    //}
    //
    //Use TestCleanup to run code after each test has run
    //[TestCleanup()]
    //public void MyTestCleanup()
    //{
    //}
    //
    #endregion

    /// <summary>
    ///A test for UpdateWorkItem
    ///Change Active state to Resolved
    ///</summary>
    [TestMethod()]
    public void RhinoUpdateWorkItemsForBuildActiveStateTest()
    {
      StreamReader sr = new StreamReader("BuildCompletionEventSample.xml");
      string eventXML = sr.ReadToEnd();
      string transitionFromState = "Active";
      string transitionToState = "Resolved";
      UpdateWorkItemTest(eventXML, transitionFromState, transitionToState);
    }

    /// <summary>
    ///A test for UpdateWorkItem
    ///Change state to Resolved for all work items
    ///</summary>
    [TestMethod()]
    public void RhinoUpdateWorkItemsForBuildEmptyStateTest()
    {
      StreamReader sr = new StreamReader("BuildCompletionEventSample.xml");
      string eventXML = sr.ReadToEnd();
      string transitionFromState = string.Empty;
      string transitionToState = "Resolved";
      UpdateWorkItemTest(eventXML, transitionFromState, transitionToState);
    }

    /// <summary>
    /// This method does all the heavy lifting for the UpdateWorkItemsForBuild tests
    /// </summary>
    /// <param name="EventXml"></param>
    /// <param name="transitionFromState"></param>
    /// <param name="transitionToState"></param>
    private void UpdateWorkItemTest(string eventXml, string transitionFromState, string transitionToState)
    {
      // Extract build URI and build number from BuildCompletionEvent eventXml
      XmlDocument doc = new XmlDocument();
      doc.LoadXml(eventXml);
      System.Uri buildUri = GetBuildUri(doc);
      string buildNumber = GetBuildNumber(doc);

      // Create the mock repository
      MockRepository mockRepository = new MockRepository();

      // Setup IBuildDetail mock object
      IBuildDetail buildDetailMockObject = (IBuildDetail)mockRepository.StrictMock<IBuildDetail>();
      Expect.Call(buildDetailMockObject.BuildNumber).PropertyBehavior();
      buildDetailMockObject.BuildNumber = buildNumber;

      // Setup IBuildServer mock object
      IBuildServer buildServerMockObject = mockRepository.StrictMock<IBuildServer>();
      Expect.Call(buildServerMockObject.GetAllBuildDetails(buildUri)).Return(buildDetailMockObject);

      // Setup WorkItem mock object
      IWorkItem workItemMockObject = (IWorkItem)mockRepository.StrictMock<IWorkItem>();
      Expect.Call(workItemMockObject.State).PropertyBehavior();
      workItemMockObject.State = "Active";
      Expect.Call(workItemMockObject.History).PropertyBehavior();
      workItemMockObject.Save();
      LastCall.IgnoreArguments();

      // Setup WorkItemSummary mock object
      int mockWorkItemID = 123;
      IWorkItemSummary workItemSummaryMockObject = (IWorkItemSummary)mockRepository.StrictMock<IWorkItemSummary>();
      Expect.Call(workItemSummaryMockObject.WorkItemId).Return(mockWorkItemID);

      // Setup WorkItemStore mock object
      IWorkItemStore workItemStoreMockObject = (IWorkItemStore)mockRepository.StrictMock<IWorkItemStore>();
      Expect.Call(workItemStoreMockObject.GetWorkItem(mockWorkItemID)).Return(workItemMockObject);

      // Setup TfsFactory mock object
      ITfsFactory tfsFactoryMockObject = (ITfsFactory)mockRepository.StrictMock<ITfsFactory>();
      Expect.Call(tfsFactoryMockObject.GetWorkItemStore()).Return(workItemStoreMockObject);
      Expect.Call(tfsFactoryMockObject.GetBuildServer()).Return(buildServerMockObject);
      List<IWorkItemSummary> associatedWorkItems = new List<IWorkItemSummary>();
      associatedWorkItems.Add(workItemSummaryMockObject);
      Expect.Call(tfsFactoryMockObject.GetAssociatedWorkItems(buildDetailMockObject)).Return(associatedWorkItems);

      // Put the mock objects into replay mode
      mockRepository.ReplayAll();

      // Run the test
      BuildUtilities target = new BuildUtilities();
      target.UpdateWorkItemsForBuild(tfsFactoryMockObject, eventXml, transitionFromState, transitionToState);
      Assert.AreEqual(transitionToState, workItemMockObject.State);
      string expectedHistory = string.Format("Build {0} changed state from {1} to {2}", buildNumber, "Active", transitionToState);
      Assert.AreEqual(expectedHistory, workItemMockObject.History);
      mockRepository.VerifyAll();
    }

    private System.Uri GetBuildUri(XmlDocument eventXmlDocument)
    {
      // Extract buildUri and buildNumber from BuildCompletionEvent EventXml
      XmlNode idNode = eventXmlDocument.SelectSingleNode(@"//BuildCompletionEvent/Url");
      if (idNode == null)
        throw new System.ApplicationException("Sample BuildCompletionEvent eventXml is bad, Url not found");
      string buildUrl = idNode.InnerText;
      string buildMoniker = buildUrl.Substring(buildUrl.IndexOf("=") + 1);
      string buildUri = "vstfs:///Build/Build/" + buildMoniker;
      return new System.Uri(buildUri);
    }

    private string GetBuildNumber(XmlDocument eventXmlDocument)
    {
      // Extract buildUri and buildNumber from BuildCompletionEvent EventXml
      XmlNode idNode = eventXmlDocument.SelectSingleNode(@"//BuildCompletionEvent/Id");
      if (idNode == null)
        throw new System.ApplicationException("Sample BuildCompletionEvent eventXml is bad, Id not found");
      string buildNumber = idNode.InnerText;
      return buildNumber;
    }
  }
}
